#ifndef DSPSIMULATOR_MEMORY_H
#define DSPSIMULATOR_MEMORY_H

#include <vector>
#include <bitset>
#include <memory>
#include <simulator/type/type.h>
#include <simulator/memory/segment.h>

/**
 * 内存
 */
class Memory {
private:
    // 内存中已经加载的段
    std::vector<std::shared_ptr<Segment>> m_segments;
public:
    Memory() = default;;

    Memory(const Memory&);

    /**
     * 向内存中添加一个段
     * @param segment
     */
    void addSegment(const std::shared_ptr<Segment> &segment);

    /**
     * 查找指定内存地址所在的段
     * @param address 内存地址
     * @return 地址所在的段的指针
     */
    std::shared_ptr<Segment> findSegmentByAddress(u64 address);

    /**
     * 从内存中读取N个字节
     * @param address 需要读取字节的起始内存地址
     * @param N 读取N个字节
     * @return
     */
    std::vector<u8> readNBytes(u64 address, u64 N);

    /**
     * 在内存中写入N个字节
     * @param address 需要写入字节的起始内存地址
     * @param N 写入N个字节
     */
    void writeNBytes(const std::vector<u8> &data, u64 address, u64 N);

    /**
     * 向内存中写入指定数量的bit
     * @param address 需要写入字节的起始内存地址
     * @param data 写入的bit数据
     */
    template<u64 N>
    void writeNBits(u64 address, std::bitset<N> data) {
        // 写入的bit大小必须为8的倍数
        if (N % 8 != 0)
            return;

        auto dataNum = data.to_ulong();
        std::vector<u8> dataArr;
        for (u64 i = 0; i < N / 8; i++) {
            auto dataTmp = dataNum & 0b11111111;
            dataArr.push_back(static_cast<u8>(dataTmp));
            dataNum >>= 8;
        }
        writeNBytes(dataArr, address, N >> 3);
    }
};

#endif //DSPSIMULATOR_MEMORY_H
